

#include <string.h>
#include <unistd.h>
#include "cmd_deal.h"
#include "uart_driver.h"
#include "timer_driver.h"
#include "common.h"

#include "usb_hotplug_check.h"
#include "modbus_dev_driver.h"
#include "duYa_Curtain_Ctrl_Driver.h"
#include "somfy_Curtain_Ctrl_Driver.h"

STRUCT_CMD_STATUS_INFO CmdStatusInfoStru[USB_SERIAL_AMOUNT] = {0x00};/*串口控制信息*/


/***********************************************************
*
*函数名:cmd_init
*
*功能:初始化cmd 结构体
*           channelid : 为0xff 当前设备可用使用串口的所有通道进行数据传输
*           channelid :0-7 当前设备可使用串口0-7 通道进行数据传输
*           channelid :其他 ，无法进行初始化
*返回值:0 
*************************************************************/
uint8_t cmd_init(uint8_t channelid)
{

    if ((channelid >= 0) && (channelid <= 0x07))
    {
        memset(CmdStatusInfoStru + channelid,0,sizeof(STRUCT_CMD_STATUS_INFO));
    }
    else
	{
		memset(CmdStatusInfoStru,0,sizeof(STRUCT_CMD_STATUS_INFO) * USB_SERIAL_AMOUNT);
	}

	return 0;
}

/***********************************************************
*
*函数名:cmd_send_data
*
*功能：数据发送
*
*参数: devid :设备地址 wrtype :数据操作类型：读写 datatype ：数据类型modbus数据中/功能码 非modbus协议数据中
*		startaddr :发送数据在点表中起始地址 num : 要发送的数据个数
*		proto :协议类型
*		pdata :要发送的数据
*  		
*		注意：接口中modbus 协议中需要 根据 wrtype 和 datatype 两个变量  确定要发送的功能码
*
*返回值: 0 :数据打包失败 !0 ：数据打包成功
************************************************************/
uint8_t cmd_send_data(int prototype,int devid,int wrtype,int datatype, int startaddr, int num,int * pdata,uint8_t channelid)
{

	uint8_t datalen = 0x00;
	uint8_t dataarray[255] = {0x00};
	
	uint8_t tmpfunc = datatype;
	
	switch(prototype)
	{
		case SERIAL_BUS_MODBUS_RTU:
			{
				
				datalen = modbus_device_pack_data((uint8_t)devid,(uint8_t)wrtype,&tmpfunc,(uint32_t)startaddr,(uint16_t)num,dataarray);

				CmdStatusInfoStru[channelid].sendframefuncode = tmpfunc & 0x00ff;
				CmdStatusInfoStru[channelid].senddevaddr = devid & 0x000000ff;
				
			}
			break;
		
		case SERIAL_BUS_DUYA_CURTAIN:
			{
			
				datalen = duya_curtain_control_pack_data((uint16_t)devid,(uint8_t)datatype,(uint8_t)startaddr,(uint8_t)num,pdata,dataarray);

				CmdStatusInfoStru[channelid].sendframefuncode = datatype & 0x00ff;
				CmdStatusInfoStru[channelid].senddevaddr = devid & 0x0000ffff;
			}
			break;

		case SERIAL_BUS_SOMFY_CURTAIN:
			{
				datalen = somfy_curtain_control_pack_data((uint32_t)devid,(uint16_t)datatype,(uint8_t)startaddr,(uint8_t)num,pdata,dataarray);

				CmdStatusInfoStru[channelid].sendframefuncode = datatype & 0x0000ffff;
				CmdStatusInfoStru[channelid].senddevaddr = devid & 0x00ffffff;
			}

			break;
			
		default:
			{
				return 0x00;
			}
	}

	CmdStatusInfoStru[channelid].prototype = prototype;
	CmdStatusInfoStru[channelid].sendframelen = datalen;

	memset(CmdStatusInfoStru[channelid].sendbuf,0,sizeof(CmdStatusInfoStru[channelid].sendbuf));
	memcpy(CmdStatusInfoStru[channelid].sendbuf,dataarray,CmdStatusInfoStru[channelid].sendframelen);	
	
	CmdStatusInfoStru[channelid].sendframestatusregstartaddr = (uint8_t)startaddr;
	CmdStatusInfoStru[channelid].sendframestatusregnum = (uint8_t)num;

	/*延时1s 3次*/
	CmdStatusInfoStru[channelid].sendretrynum = SEND_RETRY_NUM;
	CmdStatusInfoStru[channelid].sendtimeout = SEND_TIME_OUT;

    /*打印发送的数据*/
    LOGD("******serial send data:");
    LogOutHexString(CmdStatusInfoStru[channelid].sendbuf,CmdStatusInfoStru[channelid].sendframelen);

	return (CmdStatusInfoStru[channelid].sendframelen);
}


/***********************************************************
*
*函数名:cmd_send_data
*
*功能：数据发送
*
*参数: 无
*
*返回值: 0
****************************************************************/
uint8_t cmd_recv_data(uint8_t channelid)
{

	uint8_t len = 0x00;

	STRUCT_CMD_STATUS_INFO * pcmdstatusinfo = CmdStatusInfoStru + channelid;
	
	/*当前处于设备数据发送状态*/
	if (pcmdstatusinfo->sendstatus != SEND_FINISH_STATUS)
	{
		pcmdstatusinfo->recvstatus = RECV_IDLE_STATUS;
		return 0;
	}

    /*打印接收到的数据*/
    LOGD("***serial channel %d receive data:",channelid);
    LogOutHexString(pcmdstatusinfo->recvbuf,pcmdstatusinfo->recvframelen);

	/*根据不同的协议 调用不同的解析文件*/
	switch(pcmdstatusinfo->prototype)
	{
		case SERIAL_BUS_MODBUS_RTU:
			{
				len = modbus_device_unpack_data(pcmdstatusinfo->recvbuf,pcmdstatusinfo->recvframelen,(uint8_t)pcmdstatusinfo->senddevaddr,\
					(uint8_t)pcmdstatusinfo->sendframefuncode,pcmdstatusinfo->sendframestatusregstartaddr,pcmdstatusinfo->sendframestatusregnum);
			}
			break;
		case SERIAL_BUS_DUYA_CURTAIN:
			{
				len = duya_curtain_control_unpack_data(pcmdstatusinfo->recvbuf,pcmdstatusinfo->recvframelen,(uint16_t)pcmdstatusinfo->senddevaddr,\
					(uint8_t)pcmdstatusinfo->sendframefuncode,pcmdstatusinfo->sendframestatusregstartaddr,pcmdstatusinfo->sendframestatusregnum);
			}
			break;

		case SERIAL_BUS_SOMFY_CURTAIN:
			{
				len = somfy_curtain_control_unpack_data(pcmdstatusinfo->recvbuf,pcmdstatusinfo->recvframelen,pcmdstatusinfo->senddevaddr,\
					pcmdstatusinfo->sendframefuncode,pcmdstatusinfo->sendframestatusregstartaddr,pcmdstatusinfo->sendframestatusregnum);		
			}
			break;
			
		default:
			break;
	}

	if (len >0)
	{
		pcmdstatusinfo->sendstatus = SEND_ACK_STATUS;
	}
	
	pcmdstatusinfo->recvstatus = RECV_IDLE_STATUS;
	pcmdstatusinfo->recvframelen = 0x00;	

	return 0;
}


/***********************************************************
*
*函数名:cmd_read_data
*
*功能：读取从设备获取到的信息
*
*参数: 无
*
*返回值: 0
****************************************************************/
uint8_t cmd_read_data(int prototype,int devid,int wrtype,int datatype, int startaddr, int num,int * pvalue)
{

	uint8_t len = 0x00;

	/*根据不同的协议 调用不同的函数接口*/
	switch(prototype)
	{
		case SERIAL_BUS_MODBUS_RTU:
			{
			}
			break;
		case SERIAL_BUS_DUYA_CURTAIN:
			{
				len = duya_curtain_control_read_data((uint16_t)devid,(uint8_t)datatype,(uint8_t)startaddr,(uint8_t)num,(uint8_t *)pvalue);
			}
			break;

		case SERIAL_BUS_SOMFY_CURTAIN:
			break;
			
		default:
			break;
	}

	/*没有可读取的数据*/
	if (len == 0x00)
	{
		memset(pvalue,0,sizeof(pvalue));
	}
	
	return 0;
	
}

/**************************************************************
*
*函数名:cmd_get_send_state
*
*功能：获取当前发送设备状态
*
*参数：无
*
*返回值：当前发送状态
****************************************************************/
uint8_t cmd_get_send_state(uint8_t channelid)
{
	return (CmdStatusInfoStru[channelid].sendstatus);
}

/**************************************************************
*
*函数名:cmd_get_recv_state
*
*功能：获取当前设备接收状态
*
*参数：无
*
*返回值：当前接收状态
****************************************************************/
uint8_t cmd_get_recv_state(uint8_t channelid)
{
	return (CmdStatusInfoStru[channelid].recvstatus);
}

/**************************************************************
*
*函数名:cmd_clear_send_state
*
*功能：清楚设备当前的发送状态
*
*参数：status :要设置的状态值
*
*返回值：要设置的状态值
****************************************************************/
uint8_t cmd_clear_send_state(uint8_t channelid,uint8_t status)
{
    return (CmdStatusInfoStru[channelid].sendstatus = status);
}


/**************************************************************
*
*函数名:cmd_clear_recv_state
*
*功能：清楚设备当前的接收状态
*
*参数：status :要设置的状态值
*
*返回值：要设置的状态值
****************************************************************/
uint8_t cmd_clear_recv_state(uint8_t channelid,uint8_t status)
{
    return (CmdStatusInfoStru[channelid].recvstatus = status);
}

/**************************************************************
*
*函数名:cmd_get_device_ctrl_channel
*
*功能：获取当前设备的设备控制通道
*
*参数：prototype :设备对应的控制协议
*		channel :控制信号传输通道
*
*返回值：0:通道值获取成功      				 
		!0 :通道值获取失败
****************************************************************/
uint32_t cmd_get_device_control_channel(int prototype,uint8_t *channel)
{

	uint32_t ret = 0x00;
	switch (prototype)
	{
		case SERIAL_BUS_MODBUS_RTU:
			{
				ret = modbus_device_get_cmd_channel(channel);
			}
			break;
		
		case SERIAL_BUS_DUYA_CURTAIN:
			{
			
				ret = duya_curtain_get_cmd_channel(channel);
			}
			break;

		case SERIAL_BUS_SOMFY_CURTAIN:
			{
				ret = somfy_curtain_get_cmd_channel(channel);
			}

			break;
			
		default:
			{
				return 0x01;
			}
	}

	return ret;
}


/**************************************************************
*
*函数名:cmd_clear_recv_state
*
*功能：检测当前超时时间内是否能够进行数据发送 ：等待发送空闲状态
*
*参数：delay ：等待超时的最大时间    ：等待时间  = delay *10ms
*
*返回值：0:等待超时，在当前时间段内无法进行数据发送      				 
		!0 :当前状态空闲能够进行数据发送
****************************************************************/
uint32_t cmd_wait_send_idle_state_timeout(uint8_t cmdstruindex,uint32_t delay)
{

    /*判断当前状态是否能够发送数据 ,超时时间 2s：默认等待第一个缓冲区*/
    do{
        if ((CmdStatusInfoStru[cmdstruindex].sendstatus != SEND_IDLE_STATUS))
        {
            usleep(10000);
        }
        else{
            break;
        }
    }while(delay --);

	if (delay != 0x00)
	{
		CmdStatusInfoStru[cmdstruindex].sendstatus = SEND_START_STATUS;
	}
	
	return  delay;
}

/**************************************************************
*
*函数名:cmd_ajust_recv_timeout
*
*功能：根据串口波特率自动调节串口接收等待超时
*
*参数：4800 以下: 80ms 
*
*返回值：0
****************************************************************/
uint32_t cmd_ajust_recv_timeout(uint32_t bautrate)
{
	if (bautrate > 4800)
	{
		return 40000;/*40ms*/
	}
	else
	{
		return (40000 * 2);
	}
}


/***************************************ttl send & recv***********************************/
/**************************************************************
*
*函数名:ttl_send_data
*
*作用：串口数据发送
*
*参数 :fd :串口文件描述符
*返回值: 0：发送失败 ！0 ：发送成功
****************************************************************/
int ttl_send_data(uint8_t channelid)
{

    uint8_t timercnt = 0x00;
	uint8_t datlen = 0x00;

	/*当前串口状态异常，直接退出*/
	if (((UsbSerialHotplugDetectionStru.usbserialhotplugstats >> (channelid << 1)) & 0x00000003) != USB_SERIAL_INIT_OK)
	{
		deinit_serial(UsbSerialHotplugDetectionStru.usbserialfd[channelid]);
		UsbSerialHotplugDetectionStru.usbserialfd[channelid] = -1;

		return -1;
	}

    /*当前没有数据发送*/
	if ((CmdStatusInfoStru[channelid].sendstatus != SEND_START_STATUS) ||(CmdStatusInfoStru[channelid].sendframelen == 0x00))
	{

	    CmdStatusInfoStru[channelid].sendframelen = 0x00;
        CmdStatusInfoStru[channelid].sendstatus = SEND_IDLE_STATUS;

		return 0;
	}

	do
	{
		//////////////////////////////////////////////////////////////////////////////////
		serial_send_data(UsbSerialHotplugDetectionStru.usbserialfd[channelid],CmdStatusInfoStru[channelid].sendbuf,CmdStatusInfoStru[channelid].sendframelen);
        CmdStatusInfoStru[channelid].sendstatus = SEND_FINISH_STATUS;

		/////////////////////////////////////////////////////////////////////////////////
		do{
			timercnt ++;
			if(timercnt <= 0x03)
			{
				SEND_DELAY_TIME;
				if (CmdStatusInfoStru[channelid].sendstatus == SEND_ACK_STATUS)
				{
					break;
				}
			}
			else
			{
				timercnt = 0x00;
				break;
			}
		}while(1);

		if (CmdStatusInfoStru[channelid].sendstatus == SEND_ACK_STATUS)
		{
			break;
		}

		/***/
		LOGD("send no ack retry %d------",4 - CmdStatusInfoStru[channelid].sendretrynum);
	}while(-- CmdStatusInfoStru[channelid].sendretrynum );

	if (CmdStatusInfoStru[channelid].sendretrynum == 0x00)
    {
		/*发送超时:无响应*/
		CmdStatusInfoStru[channelid].sendstatus = SEND_TIMEOUT_STATUS;
    } else{
        datlen = CmdStatusInfoStru[channelid].sendframelen;
    }

	CmdStatusInfoStru[channelid].sendframelen = 0x00;
	return (datlen);
}

/**************************************************************
*
*函数名:ttl_recv_data :同时监听 多个串口数据接收
*
*作用：串口数据接收
*
*参数 :fd :串口文件描述符
*返回值: 0：
****************************************************************/
int ttl_recv_data(uint8_t channelid)
{

	uint8_t i = 0;
	uint8_t data[256] = {0x00};

	uint32_t recvdelay = 0x00;

	int len = 0x00;

	/////////////////////////////////////////////////////////
	/*当前串口状态异常，直接退出*/
	if (((UsbSerialHotplugDetectionStru.usbserialhotplugstats >> (channelid << 1)) & 0x00000003) != USB_SERIAL_INIT_OK)
	{

		deinit_serial(UsbSerialHotplugDetectionStru.usbserialfd[channelid]);
		UsbSerialHotplugDetectionStru.usbserialfd[channelid] = -1;

		return -1;
	}

	/////////////////////////////////////////////////////////
    /*无数据正在处理*/
	if (CmdStatusInfoStru[channelid].recvstatus != RECV_FINISH_STATUS)
	{
		/*开始接收新的一帧数据*/
		if ((CmdStatusInfoStru[channelid].recvstatus == RECV_IDLE_STATUS)||(CmdStatusInfoStru[channelid].recvstatus == RECV_OVERFLOW_STATUS) ||(CmdStatusInfoStru[channelid].recvstatus == RECV_ACK_STATUS))
		{

			CmdStatusInfoStru[channelid].recvstatus = RECV_START_STATUS;
			CmdStatusInfoStru[channelid].recvframelen = 0x00;

			/*read data*/
			recvdelay = cmd_ajust_recv_timeout(UsbSerialHotplugDetectionStru.usbserialbautrate[channelid]);
			len  = serial_recv_data(UsbSerialHotplugDetectionStru.usbserialfd[channelid],data,sizeof (data),recvdelay);

			/*No data recv*/
			if ((len <= 0))
			{
				CmdStatusInfoStru[channelid].recvstatus = RECV_IDLE_STATUS;
				return 0;
			}

			memcpy(CmdStatusInfoStru[channelid].recvbuf,data,len);
			CmdStatusInfoStru[channelid].recvframelen = len;

			CmdStatusInfoStru[channelid].recvstatus = RECV_FINISH_STATUS;

			/*delay :40ms :根据不同的通道 选择不同的超时处理函数*/
			cmd_recv_data(channelid);
		}
	}
    return 0;
}



